/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package DSB.Controller;

import DSB.Model.Kaart.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileFilter;
import java.util.HashMap;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 *
 * @author Gebruiker
 * instantiatie van de klasse met de variabelen
 */
public class KaartController {

    private static KaartController kaartController = new KaartController();
    private File dir = new File("./Kaarten"); 
    private String _region;
    private String _route;
    
    private KaartController(){}
    
    /**
     *
     * @return Aanmaken van de singleton pattern welke maar 1 keer de kaartcontroller aanmaakt
     */
    public static KaartController getInstance()
    {
        if(kaartController == null){
            kaartController  = new KaartController();
        }
        return kaartController;
    }  
    
    /**
     *
     * @return inlezen van de desbetreffende plaats waar de route gelopen kan worden
     */
    public File[] GetRegions()
    {  
        File[] subDirs = null;
        if(dir != null)
        {
            subDirs = dir.listFiles(new FileFilter() {  
                @Override
                public boolean accept(File pathname) {
                    return (pathname.isDirectory() && !pathname.getName().equals(".svn")); 
                }  
            }); 
        }
       return subDirs; 
    }
    
    /**
     *
     * @param region
     * @return ophalen en terugsturen van de desbetreffende route afhankelijk van de gekozen regio.
     */
    public File[] GetRoutes(String region)
    {  
        File[] subDirs = null;
        if(dir != null)
        {
            File route = new File(dir.getPath() + "/" + region);
            subDirs = route.listFiles(new FileFilter() {  
                @Override
                public boolean accept(File pathname) {
                    return (pathname.isDirectory() && !pathname.getName().equals(".svn")); 
                }  
            }); 
        }
       return subDirs; 
    }
    
    //rechtstreeks inladen van de kaart zonder alle waypoints en pois, ivm performance
    
    /**
     *
     * @param region
     * @param route
     * @return ophalen van de juiste plattegrond met de gekozen route
     */
    public BufferedImage getMap(String region, String route)
    {
        BufferedImage img = null;
        try {
            img = ImageIO.read(new File(dir.getPath() + "/" + region + "/" + route + "/Map/Map.JPG"));
        } catch (Exception e) {
        }
        
        return img;
    }
    
    /**
     *
     * @param region
     * @param route
     * @return ophalen en verwerken van de coordinaten van de map. 
     */
    public HashMap<String, Coordinaat> getMapCoordinates(String region, String route)
    {
        HashMap<String, Coordinaat> coordinates = new HashMap();
        
        DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance();

        try {
            DocumentBuilder db = builder.newDocumentBuilder();
            String path  = "Kaarten/" + region + "/" + route + "/Map/Map.xml";
            Document file = db.parse(path);

            Element root = file.getDocumentElement();
            NodeList nl = root.getChildNodes();
            if (nl != null && nl.getLength()  > 0)
            {
                for(int i = 0; i < nl.getLength(); i++)
                {
                    if(nl.item(i).getNodeType() == 1)
                    {
                        Element res = (Element) nl.item(i);
                        NodeList latitude = res.getElementsByTagName("latitude");
                        NodeList longitude = res.getElementsByTagName("longitude");

                        if(latitude.getLength() == 1 && longitude.getLength() == 1)
                        {
                            Coordinaat coord = new Coordinaat(Double.parseDouble(latitude.item(0).getFirstChild().getNodeValue()), 
                                    Double.parseDouble(longitude.item(0).getFirstChild().getNodeValue()));
                            coordinates.put(nl.item(i).getNodeName(), coord);
                        }
                    }
                }
                
                return coordinates;
            }
            return null;
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
            return null;
        }
    }
    
    /**
     *
     * @param region
     * @param route
     * Methode om de kaart te laden en alle poi's op de kaart te tekenen
     */
    public void LoadMap(String region, String route)
    {
        if(region != null && route != null)
        {
            _region = region;
            _route = route;
            BufferedImage image = getMap(region, route);
            HashMap<String, Coordinaat> coordinates = getMapCoordinates(region, route);
            
            if(image != null && coordinates != null && coordinates.size() == 4)
            {
            Map kaart = new Kaart(image,
                    coordinates.get("upperleft"), 
                    coordinates.get("upperright"), 
                    coordinates.get("lowerleft"), 
                    coordinates.get("lowerright"), 
                    region, 
                    route);
            
            kaart = LoadWaypoints(region, route, kaart);
            kaart = LoadPois(region, route, kaart);
            
            try {
                ImageIO.write(kaart.DrawOnMap(), "PNG", new File("Resources/images", "combined.png"));
            } catch (Exception ex) {
                Logger.getLogger(POI.class.getName()).log(Level.SEVERE, null, ex);
            }
                    
            ToeristController.getInstance().setMap(kaart);
            }
        }
    }
    
    /**
     *
     * @return
     */
    public String getSelectedRegion(){
        if(_region != null)
        {
            return _region;
        }
        else
        {
            return "";
        }
    }
    
    /**
     *
     * @return
     */
    public String getSelectedRoute(){
        if(_route != null)
        {
            return _route;
        }
        else
        {
            return "";
        }
    }
    
    private Map LoadPois(String region, String route, Map map)
    {
        File[] pois = null;
        List<POI> poiList;
        if(dir != null)
        {
            File poiLocation = new File(dir.getPath() + "/" + region + "/" + route + "/POI");
            pois = poiLocation.listFiles(new FileFilter() {  
                @Override
                public boolean accept(File pathname) {
                    return (!pathname.isDirectory() && pathname.getName().endsWith(".xml")); 
                }  
            }); 
        }
        
        DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance();
        
        for(int i=0; i < pois.length; i++)
        {
            try {
                DocumentBuilder db = builder.newDocumentBuilder();
                
                String path  = dir.getPath() + "/" + region + "/" + route + "/POI/" + pois[i].getName();
                Document file = db.parse(path);
                
                Element root = file.getDocumentElement();
                    
                NodeList latitude = root.getElementsByTagName("latitude");
                NodeList longitude = root.getElementsByTagName("longitude");
                NodeList straal = root.getElementsByTagName("straal");
                NodeList name = root.getElementsByTagName("name");
                            
                Coordinaat coord = null;

                if(latitude.getLength() == 1 && longitude.getLength() == 1)
                {
                    coord = new Coordinaat(Double.parseDouble(latitude.item(0).getFirstChild().getNodeValue()), 
                            Double.parseDouble(longitude.item(0).getFirstChild().getNodeValue()));
                }

                if (coord != null && straal.getLength() > 0 && name.getLength() > 0)
                {
                    map = new POI(map, coord, Integer.parseInt(straal.item(0).getFirstChild().getNodeValue()), name.item(0).getFirstChild().getNodeValue().toString());
                }               
            } catch (Exception ex) {
                System.out.println(ex.getMessage());
                return map;
            }
        }
        
        return map;
    }
    
    private Map LoadRoute(String region, String route, Map map)
    {
        SortedMap<Integer, String> routeList = new TreeMap<Integer, String>();
        
        DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance();
        try 
        {
            DocumentBuilder db = builder.newDocumentBuilder();

            String path  = dir.getPath() + "/" + region + "/" + route + "/Route/Route.xml";
            Document file = db.parse(path);

            Element root = file.getDocumentElement();

            NodeList routeOrder = root.getElementsByTagName("routeorder");

            if(routeOrder != null && routeOrder.getLength() == 1)
            {
                Element routeElement = (Element) routeOrder.item(0);
                NodeList waypoints = routeElement.getElementsByTagName("waypoint");

                if(waypoints != null && waypoints.getLength() > 0)
                {
                    for(int i = 0; i < waypoints.getLength(); i++)
                    {
                        int order = Integer.parseInt(waypoints.item(i).getAttributes().getNamedItem("order").getNodeValue().toString());
                        String waypoint = waypoints.item(i).getFirstChild().getNodeValue();
                        if(order > 0 && waypoint != null && !waypoint.equals(""))
                        {
                            routeList.put(order, waypoint);
                        }
                    }
                }
            }
            return new Route(map, routeList, region, route);
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
            return map;
        }
    }
    
    private Map LoadWaypoints(String region, String route, Map map)
    {
        DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance();
        
        try {
            DocumentBuilder db = builder.newDocumentBuilder();

            String path  = dir.getPath() + "/" + region + "/" + route + "/Waypoint/Waypoint.xml";
            Document file = db.parse(path);

            if(file != null)
            {
                Element root = file.getDocumentElement();
                NodeList waypoints = root.getElementsByTagName("waypoint");
                
                if(waypoints != null && waypoints.getLength() > 0)
                {
                    for(int i = 0; i < waypoints.getLength(); i++)
                    {
                        if(waypoints.item(i).getNodeType() == 1)
                        {
                            Element waypoint = (Element) waypoints.item(i);
                            NodeList latitudeNode = waypoint.getElementsByTagName("latitude");
                            NodeList longitudeNode = waypoint.getElementsByTagName("longitude");
                            NodeList nameNode = waypoint.getElementsByTagName("name"); 
                            NodeList visibilityNode = waypoint.getElementsByTagName("visibility");
                        
                            if(nameNode.getLength() > 0 && latitudeNode.getLength() > 0 && longitudeNode.getLength() > 0)
                            {
                                Coordinaat coordinate = new Coordinaat(Double.parseDouble(latitudeNode.item(0).getFirstChild().getNodeValue()),
                                                                    Double.parseDouble(longitudeNode.item(0).getFirstChild().getNodeValue()));
                                String name = nameNode.item(0).getFirstChild().getNodeValue();
                                boolean visibility = Boolean.parseBoolean(visibilityNode.item(0).getFirstChild().getNodeValue());
                                map = new Waypoint(map, name, visibility, coordinate);
                            }
                        }
                    }
                }           
            }
            return map;
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
            return map;
        }
    }
}
